package de.playmee.handler;

import java.util.ArrayList;
import java.util.List;

import android.content.ContentValues;
import android.database.Cursor;
import android.util.Log;

import de.playmee.Channel;
import de.playmee.ChannelTrackRating;
import de.playmee.Track;

public class ChannelTrackRatingHandler extends DatabaseHandler {

	private final String TAG = "ChannelTrackRatingHandler";

	public final static String KEY_CHANNELID = "channelid";
	public final static String KEY_TRACKID = "trackid";
	public final static String KEY_RATING = "rating";

	public final static String DATABASE_TABLE = "channeltrackrating";

	public final static String DATABASE_CREATE = "create table " + DATABASE_TABLE
			+ " (" + KEY_CHANNELID + " bigint not null, "
			+ KEY_TRACKID + " bigint not null, "
			+ KEY_RATING + " bigint not null," + "primary key(" + KEY_CHANNELID + ", " + KEY_TRACKID + ")" + ");";

	private MusicHandler mHandler;
	
	public ChannelTrackRatingHandler(DatabaseHelper dbHelper, MusicHandler mHandler) {
		super(dbHelper);
		this.mHandler = mHandler;
		// now available: dbHelper, db, DELIMITER
	}

	/**
	 * inserts channel-track ratings into the database
	 * 
	 * @param channel
	 * @param trackIds
	 * @return true if inserting was successful for all tracks, false otherwise
	 */
	public boolean insertChannelTrackRatings(Channel channel, ArrayList<Long> trackIds) {
		Log.i(TAG, "Inserting channel-track ratings for channel " + channel.getId() + "...");
		long channelId = channel.getId();
		boolean no_error = true;
		
		if (trackIds == null) {
			trackIds = mHandler.loadTrackIds();
		}

		for (long trackId : trackIds) {
			if (trackId <= 0)
				continue;
			ContentValues values = new ContentValues();
			values.put(KEY_CHANNELID, channelId);
			values.put(KEY_TRACKID, trackId);
			values.put(KEY_RATING, 0);

			synchronized (db) {
				if (!ChannelTrackRatingExists(channelId, trackId)) {
					long id = db.insert(DATABASE_TABLE, null, values);
					if (id == -1) {
						no_error = false;
					}
				}
			}
		}

		return no_error;
	}
	
	/**
	 * inserts channel-track ratings into the database
	 * 
	 * @param channels
	 * @param trackId
	 * @return true if inserting was successful for all channels, false otherwise
	 */
	public boolean insertChannelTrackRatings(List<Long> channelIds, long trackId) {
		Log.i(TAG, "Inserting channel-track ratings for track " + trackId + "...");
		boolean no_error = true;
		
		if (trackId <= 0)
			return false;
		
		for (long channelId : channelIds) {
			ContentValues values = new ContentValues();
			values.put(KEY_CHANNELID, channelId);
			values.put(KEY_TRACKID, trackId);
			values.put(KEY_RATING, 0);
			
			synchronized (db) {
				if (!ChannelTrackRatingExists(channelId, trackId)) {
					long id = db.insert(DATABASE_TABLE, null, values);
					if (id == -1) {
						no_error = false;
					}
				}
			}
		}

		return no_error;
	}

	/**
	 * updates a channel-track rating
	 * 
	 * @param channel
	 * @param track
	 * @param difference
	 * @return true if rating was updating was successful, false otherwise
	 */
	public boolean updateChannelTrackRating(Channel channel, Track track, int difference) {
		Log.i(TAG, "Updating channel-track rating for channel " + channel.getId()
				+ " and track " + track.getIdDatabase() + "...");
		ContentValues values = new ContentValues();
		values.put(KEY_CHANNELID, channel.getId());
		values.put(KEY_TRACKID, track.getIdDatabase());

		ChannelTrackRating rating = getChannelTrackRating(channel, track);

		long value = rating.getRatingValue();
		value += difference;
		values.put(KEY_RATING, value);

		synchronized (db) {
			return db.update(DATABASE_TABLE, values,
					KEY_CHANNELID + "=" + channel.getId() + " AND " + KEY_TRACKID
							+ "=" + track.getIdDatabase(), null) != -1;
		}
	}
	
	/**
	 * resets the channel-track rating to the value 0
	 * 
	 * @param channelId
	 * @return true if ratings were updated successful, false otherwise
	 */
	public boolean reset(long channelId) {
		Log.i(TAG, "Resetting the channel-track-ratings for channel " + channelId);
		ContentValues values = new ContentValues();
		values.put(KEY_RATING, 0);
		
		synchronized (db) {
			return db.update(DATABASE_TABLE, values,
					KEY_CHANNELID + "=" + channelId, null) != -1;
		}
	}
	
	/**
	 * checks if a particular channel-track-rating exists
	 * 
	 * @param channelId
	 * @param trackId
	 * @return true if the channel-track-rating exists, false otherwise
	 */
	public boolean ChannelTrackRatingExists(long channelId, long trackId) {
		synchronized (db) {
			Cursor cursor = db.query(DATABASE_TABLE, null,
					KEY_CHANNELID + "=" + channelId + " AND " + KEY_TRACKID + "=" + trackId,
					null, null, null, null);
			if (cursor != null && cursor.moveToFirst())
				return true;
			return false;
		}
	}

	/**
	 * loads a channel-track rating
	 * 
	 * @param channel
	 * @param track
	 * @return ChannelTrackRating
	 */
	public ChannelTrackRating getChannelTrackRating(Channel channel, Track track) {
		Log.i(TAG, "Queriying channel-track rating (" + channel.getId() + ", "
						+ track.getIdDatabase() + ")...");
		ChannelTrackRating rating = new ChannelTrackRating();

		synchronized (db) {
			Cursor cursor = db.query(true, DATABASE_TABLE, null,
					KEY_CHANNELID + "=" + channel.getId() + " AND " + KEY_TRACKID
							+ "=" + track.getIdDatabase(), null, null, null, null, null);
			if (cursor != null && cursor.moveToFirst()) {
				rating = cursorToRating(cursor);
				cursor.close();
				return rating;
			}
		}

		return null;
	}

	/**
	 * loads all channel-track ratings of a channel
	 * 
	 * @param channel
	 * @return List
	 */
	public List<ChannelTrackRating> getChannelTrackRatings(Channel channel) {
		Log.i(TAG, "Queriying channel-track ratings of channel " + channel.getId() + "...");
		List<ChannelTrackRating> ratings = new ArrayList<ChannelTrackRating>();

		Cursor cursor = db.query(DATABASE_TABLE, null, KEY_CHANNELID
				+ " = " + channel.getId(), null, null, null, null);

		if (cursor != null && cursor.moveToFirst()) {
			while (!cursor.isAfterLast()) {
				ChannelTrackRating rating = cursorToRating(cursor);
				ratings.add(rating);
				cursor.moveToNext();
			}
			cursor.close();

			return ratings;
		}

		return null;
	}

	/**
	 * creates a channel-track rating
	 * 
	 * @param cursor
	 * @return ChannelTrackRating
	 */
	private ChannelTrackRating cursorToRating(Cursor cursor) {
		ChannelTrackRating rating = new ChannelTrackRating();
		rating.setChannelId(cursor.getLong(cursor.getColumnIndex(KEY_CHANNELID)));
		rating.setTrackId(cursor.getLong(cursor.getColumnIndex(KEY_TRACKID)));
		rating.setRatingValue(cursor.getLong(cursor.getColumnIndex(KEY_RATING)));

		return rating;
	}
}